package karpiel.boguchwal.wojciech

package object przemek {

  class PrzemekException(val msg: String) extends RuntimeException(msg)

  class TypecheckException(str: String) extends PrzemekException(str) {
    def this() = this("Coś się wysypało. DOZRO: Napisać wartościową wiadomość o błędize xD")
  }

  implicit class AstUtils(val self: Ast) extends AnyVal {
    def sigmaElimHelper(index: Int): Ast = Utils.sigmaElimHelper(self, index)

    def applyToSubtrees(fn: Ast => Ast): Ast = Utils.applyToSubTrees(self, fn)

    def prettyPrint(implicit ctx: Context): String = Utils.prettyPrint(self)

    def shiftn(n: Int): Ast = Utils.shift(self, 0, n)

    final def inferType(implicit ctx: Context, cache: Cache): Ast = TypeInferer.inferType(self)

    final def normalized(implicit ctx: Context, cache: Cache): Ast = TypeNormalizer.normalized(self)

    final def equalNormalized(other: Ast)(implicit ctx: Context, cache: Cache): Boolean = {
      self.normalizeCC == other.normalizeCC
    }

    final def getAs[T <: Ast](implicit ctx: Context, cache: Cache): T = self.normalized.asInstanceOf[T]

    final def assertEquals(other: Ast)(implicit ctx: Context, cache: Cache): Unit = {
      assertEqualsOpt(other)
    }

    final def assertEqualsOpt(other: Ast)(implicit ctx: Context, cache: Cache): Unit = {
      if (!equalNormalized(other))
        throw new TypecheckException(self.normalized + " !== " + other.normalized)
    }

    //CC =currentContext
    def inferCC(implicit ctx: Context, cache: Cache): Ast =
      inferType

    //CC =currentContext
    def normalizeCC(implicit ctx: Context, cache: Cache): Ast =
      normalized
  }

  implicit class UniversalOps[T](val self: T) extends AnyVal {
    def |[U](fn: T => U) = fn(self)
  }

}
